﻿#include "WelfareDescEx.h"

#include "proto_welfare.nanopb.h"
#include "DescStore/RewardDesc.h"
#include "DescStore/WelfareDeleteDesc.h"
#include "DescStore/WelfareDesc.h"
#include "DescStore/WelfareNodeDesc.h"

#include "NFLogicCommon/NFItemDefine.h"
#include "NFLogicCommon/NFWelfareConfOne.h"

WelfareDescEx::WelfareDescEx()
{
    if (EN_OBJ_MODE_INIT == NFShmMgr::Instance()->GetCreateMode())
    {
        CreateInit();
    }
    else
    {
        ResumeInit();
    }
}

WelfareDescEx::~WelfareDescEx()
{
}

int WelfareDescEx::CreateInit()
{
    m_dwLastChangeUnixSec = 0;
    return 0;
}

int WelfareDescEx::ResumeInit()
{
    return 0;
}

int WelfareDescEx::Load()
{
    return 0;
}

int WelfareDescEx::CheckWelfareNodeDesc(const E_Welfare* pDesc)
{
    int iRetCode = 0;
    auto vecNode = WelfareNodeDesc::Instance()->GetDescByWelfareId(pDesc->m_welfareId);
    if (vecNode.size() > WELFARE_DEFINE_ONE_NODE_NUM_MAX)
    {
        CHECK_ERR(0, -1, "the welfare:{} has nodes:{} >= the max:{}", pDesc->m_welfareId, vecNode.size(), WELFARE_DEFINE_ONE_NODE_NUM_MAX);
    }

    std::set<int> setNodeId;
    for (size_t j = 0; j < vecNode.size(); j++)
    {
        auto pNodeDesc = vecNode[j];
        CHECK_NULL(0, pNodeDesc);

        if (setNodeId.find(pNodeDesc->m_nodeId) != setNodeId.end())
        {
            CHECK_EXPR(0, -1, "the welfare:{} has repeat nodeId:{}", pDesc->m_welfareId, pNodeDesc->m_nodeId);
        }
        setNodeId.insert(pNodeDesc->m_nodeId);

        iRetCode = CheckWelfareNodeWithType(pDesc, pNodeDesc);
        CHECK_ERR(0, iRetCode, "CheckWelfareNodeWithType Failed");

        if (pNodeDesc->m_nodeId < 1 || pNodeDesc->m_nodeId > WELFARE_DEFINE_ONE_NODE_NUM_MAX)
        {
            CHECK_ERR(0, -1, "the welfare:{} id:{} out of range, must int [1,{}]", pDesc->m_welfareId, pNodeDesc->m_nodeId, WELFARE_DEFINE_ONE_NODE_NUM_MAX);
        }

        if (pNodeDesc->m_type == WELFARE_NODE_TYPE_NULL)
        {
            continue;
        }

        iRetCode = CheckWelfareNodeClickCond(pNodeDesc->m_stClickCond);
        CHECK_ERR(0, iRetCode, "CheckAndSetWelfareNodeClickCond Failed welfare:{} nodeId:{} m_stClickCond:{}", pDesc->m_welfareId, pNodeDesc->m_nodeId, pNodeDesc->m_stClickCond.ShortDebugString());

        for (int x = 0; x < (int)pNodeDesc->m_astAward.size(); x++)
        {
            const auto& stWelfareNodeAward = pNodeDesc->m_astAward[x];
            iRetCode = CheckWelfareNodeAward(stWelfareNodeAward);
            CHECK_ERR(0, iRetCode, "CheckWelfareNodeAward Failed welfare:{} nodeId:{} x:{} m_astAward:{}", pDesc->m_welfareId, pNodeDesc->m_nodeId, x, stWelfareNodeAward.ShortDebugString());
        }
    }

    for (uint32_t nodeId = 1; nodeId <= WELFARE_DEFINE_ONE_NODE_NUM_MAX; nodeId++)
    {
        if (setNodeId.empty())
        {
            break;
        }

        if (setNodeId.find(nodeId) == setNodeId.end())
        {
            CHECK_ERR(0, -1, "welfareId:{} node must inc form 1 to {}, dwNodeID:{}" " not config", pDesc->m_welfareId, WELFARE_DEFINE_ONE_NODE_NUM_MAX, nodeId);
        }
        setNodeId.erase(nodeId);
    }

    return 0;
}

int WelfareDescEx::CheckWhenAllDataLoaded()
{
    int iRetCode = 0;
    uint32_t dwUnixSec = NF_ADJUST_TIMENOW();
    for (int i = 0; i < WelfareDesc::Instance()->GetResNum(); i++)
    {
        auto pDesc = WelfareDesc::Instance()->GetDescByIndex(i);
        CHECK_NULL(0, pDesc);
        if (pDesc->m_stSvrOpenTimeBefore.m_szTime_t != 0 && pDesc->m_stSvrOpenTimeAfter.m_szTime_t >= pDesc->m_stSvrOpenTimeBefore.m_szTime_t)
        {
            CHECK_ERR(0, -1, "welfareId:{} m_stSvrOpenTimeAfter:{}:{} must < m_stSvrOpenTime:{}:{}", pDesc->m_welfareId, pDesc->m_stSvrOpenTimeAfter.m_szTime_t, pDesc->m_stSvrOpenTimeAfter.m_szTime.ToString(), pDesc->m_stSvrOpenTimeBefore.m_szTime_t,
                      pDesc->m_stSvrOpenTimeBefore.m_szTime.ToString());
        }

        iRetCode = CheckShowLevelRange(pDesc->m_openPlayerLevel, pDesc->m_showPlayerLevel);
        CHECK_ERR(0, iRetCode, "player show level CheckLevelRange failed");

        if (pDesc->m_astServerOpenUnixTimeRange.size() > 0 && pDesc->m_openDayGameSvrOpenDay.m_iMin > 0)
        {
            //开始时刻和开服时间段，只运行开一个
            CHECK_ERR(0, -1, "the welfare:{} has openDayGameSvrOpenDay:{} and astServerOpenUnixTimeRange:{}", pDesc->m_welfareId, pDesc->m_openDayGameSvrOpenDay.m_iMin, pDesc->m_astServerOpenUnixTimeRange.size());
        }


        if (pDesc->m_astServerOpenUnixTimeRange.size() == 0 && pDesc->m_openDayGameSvrOpenDay.m_iMin <= 0)
        {
            //开始时刻和开服时间段，只运行开一个
            CHECK_ERR(0, -1, "the welfare:{} openDayGameSvrOpenDay:{} or astServerOpenUnixTimeRange:{} must config one", pDesc->m_welfareId, pDesc->m_openDayGameSvrOpenDay.m_iMin, pDesc->m_astServerOpenUnixTimeRange.size());
        }

        iRetCode = CheckWelfareWithType(pDesc);
        CHECK_ERR(0, iRetCode, "welfareId:{} CheckWelfareWithType Failed", pDesc->m_welfareId);

        if (pDesc->m_astServerOpenUnixTimeRange.size() > 0)
        {
            for (size_t j = 0; j < pDesc->m_astServerOpenUnixTimeRange.size(); j++)
            {
                iRetCode = CheckTimeRange(pDesc->m_astServerOpenUnixTimeRange[j].m_stUnixTimeRange);
                CHECK_ERR(0, iRetCode, "welfareId:{} j:{} CheckTimeRange Failed", pDesc->m_welfareId, j);
            }
        }
        else
        {
            iRetCode = CheckIntRange(pDesc->m_openDayGameSvrOpenDay);
            CHECK_ERR(0, iRetCode, "welfareId:{} CheckIntRange m_openDayGameSvrOpenDay failed", pDesc->m_welfareId);
        }

        if (pDesc->m_type == WELFARE_TYPE_EXTEND_NODE && pDesc->m_extendWelfareId > 0)
        {
            if (pDesc->m_extendWelfareId == pDesc->m_welfareId)
            {
                CHECK_ERR(0, -1, "the welfare:{} extend welfareId:{} must not equal to itself", pDesc->m_welfareId, pDesc->m_extendWelfareId);
            }

            auto pExtendDesc = WelfareDesc::Instance()->GetDesc(pDesc->m_extendWelfareId);
            CHECK_NULL_WF(pDesc->m_welfareId, pExtendDesc, "extend welfare null, welfareId:{} extend welfareId:{}", pDesc->m_welfareId, pDesc->m_extendWelfareId);

            if (pExtendDesc->m_type == WELFARE_TYPE_EXTEND_NODE)
            {
                CHECK_ERR(0, -1, "the welfare:{} extend welfareId:{} must not WELFARE_TYPE_EXTEND_NODE", pDesc->m_welfareId, pDesc->m_extendWelfareId);
            }
        }

        auto pWelfareDeleteDesc = WelfareDeleteDesc::Instance()->GetDesc(pDesc->m_welfareId);
        if (pWelfareDeleteDesc)
        {
            CHECK_ERR(0, -1, "welfareId:{} had exist in welfareDeleteDesc", pDesc->m_welfareId);
        }

        iRetCode = CheckWelfareWorldID(pDesc);
        CHECK_ERR(0, iRetCode, "CheckWelfareWorldID failed, welfareId:{}", pDesc->m_welfareId);
    }

    for (int i = 0; i < WelfareNodeDesc::Instance()->GetResNum(); i++)
    {
        auto pNodeDesc = WelfareNodeDesc::Instance()->GetDescByIndex(i);
        CHECK_NULL(0, pNodeDesc);

        if (pNodeDesc->m_welfareId == 0)
        {
            CHECK_EXPR(0, -1, "m_welfareId can not equal 0, id:{}", pNodeDesc->m_index);
        }

        if (pNodeDesc->m_nodeId < 1 || pNodeDesc->m_nodeId > WELFARE_DEFINE_ONE_NODE_NUM_MAX)
        {
            CHECK_ERR(0, -1, "nodeId err, welfareId:{} nodeId:{}", pNodeDesc->m_welfareId, pNodeDesc->m_nodeId);
        }
    }

    static NFWelfareConfOne* pstWelfareConfOne = new NFWelfareConfOne();
    pstWelfareConfOne->Reset();
    for (int i = 0; i < WelfareDesc::Instance()->GetResNum(); i++)
    {
        auto pDesc = WelfareDesc::Instance()->GetDescByIndex(i);
        CHECK_NULL(0, pDesc);

        iRetCode = CheckWelfareNodeDesc(pDesc);
        CHECK_ERR(0, iRetCode, "CheckWelfareNodeDesc Failed, welfareId:{}", pDesc->m_welfareId);

        uint32_t dwGameOpenDayBeginUnixSec = NFTimeUtility::GetTodayStartTime(dwUnixSec);
        iRetCode = pstWelfareConfOne->SetConfData(pDesc->m_welfareId, dwUnixSec, dwGameOpenDayBeginUnixSec, NFGlobalSystem::Instance()->GetGlobalPluginManager()->GetZoneID());
        CHECK_ERR(0, iRetCode, "stWelfareConfOne.SetConfData Failed, id:{}", pDesc->m_welfareId);
        pstWelfareConfOne->Reset();
    }

    m_dwLastChangeUnixSec = dwUnixSec;
    return 0;
}

int WelfareDescEx::CheckWelfareNodeClickCond(const WelfareNodeClickCond& stWelfareNodeClickCond)
{
    if (stWelfareNodeClickCond.m_openTimeMin.m_dwDay >= 3650)
    {
        CHECK_ERR(0, -1, "stWelfareNodeClickCond.m_openTimeMin.m_dwDay:{} must in [0, 3650)", stWelfareNodeClickCond.m_openTimeMin.m_dwDay);
    }
    if (stWelfareNodeClickCond.m_openTimeMin.m_dwMin >= SECONDS_ADAY)
    {
        CHECK_ERR(0, -1, "stWelfareNodeClickCond.m_openTimeMin.m_dwMin:{} must in [0, 86400)", stWelfareNodeClickCond.m_openTimeMin.m_dwMin);
    }

    if (stWelfareNodeClickCond.m_endTimeMin.m_dwDay >= 3650)
    {
        CHECK_ERR(0, -1, "stWelfareNodeClickCond.m_endTimeMin.m_dwDay:{} must in [0, 3650)", stWelfareNodeClickCond.m_openTimeMin.m_dwDay);
    }
    if (stWelfareNodeClickCond.m_endTimeMin.m_dwMin >= SECONDS_ADAY)
    {
        CHECK_ERR(0, -1, "stWelfareNodeClickCond.m_endTimeMin.m_dwMin:{} must in [0, 86400)", stWelfareNodeClickCond.m_openTimeMin.m_dwMin);
    }
    return 0;
}

int WelfareDescEx::CheckTimeRange(const UnixTimeRange& stUnixTimeRange)
{
    if (stUnixTimeRange.m_stUnixTimeOneBegin.m_szTime_t > stUnixTimeRange.m_stUnixTimeOneEnd.m_szTime_t)
    {
        CHECK_ERR(0, -1, "invalid UnixTimeRange, openTime:{} > endTime:{}", stUnixTimeRange.m_stUnixTimeOneBegin.m_szTime.ToString(), stUnixTimeRange.m_stUnixTimeOneEnd.m_szTime.ToString());
    }
    return 0;
}

int WelfareDescEx::CheckIntRange(const IntRange& stIntRange)
{
    if (stIntRange.m_iMax < stIntRange.m_iMin)
    {
        CHECK_ERR(0, -1, "invalid int range, int max:{} < int min", stIntRange.m_iMax, stIntRange.m_iMin);
    }
    return 0;
}

int WelfareDescEx::CheckLevelRange(const IntRange& stIntRange)
{
    if (stIntRange.m_iMax < 1)
    {
        CHECK_ERR(0, -1, "invalid level range, max:{} must >= 1", stIntRange.m_iMax);
    }
    return CheckIntRange(stIntRange);
}

int WelfareDescEx::CheckShowLevelRange(const IntRange& stOpenLevelIntRange, const IntRange& stShowLevelIntRange)
{
    int iRetCode = CheckLevelRange(stOpenLevelIntRange);
    CHECK_ERR(0, iRetCode, "CheckLevelRange stOpenLevelIntRange Failed");

    iRetCode = CheckLevelRange(stShowLevelIntRange);
    CHECK_ERR(0, iRetCode, "CheckLevelRange stShowLevelIntRange Failed");

    if (stOpenLevelIntRange.m_iMin > stShowLevelIntRange.m_iMin)
    {
        CHECK_ERR(0, -1, "open min level:{} > show min level", stOpenLevelIntRange.m_iMin, stShowLevelIntRange.m_iMin);
    }

    if (stOpenLevelIntRange.m_iMax > stShowLevelIntRange.m_iMax)
    {
        CHECK_ERR(0, -1, "open max level:{} > show max level", stOpenLevelIntRange.m_iMax, stShowLevelIntRange.m_iMax);
    }
    return 0;
}

int WelfareDescEx::CheckWelfareWithType(const E_Welfare* pDesc)
{
    CHECK_NULL(0, pDesc);
    int iRetCode = 0;
    switch (pDesc->m_type)
    {
        case WELFARE_TYPE_SIGN_IN:
        {
            iRetCode = CheckWelfareWithTypeSignIn(pDesc);
            break;
        }
        default:
        {
            return 0;
        }
    }
    return iRetCode;
}

int WelfareDescEx::CheckWelfareWithTypeSignIn(const E_Welfare* pDesc)
{
    CHECK_NULL(0, pDesc);
    return 0;
}

int WelfareDescEx::CheckWelfareNodeWithType(const E_Welfare* pDesc, const E_WelfareNode* pNodeDesc)
{
    CHECK_NULL(0, pDesc);
    CHECK_NULL(0, pNodeDesc);
    switch (pNodeDesc->m_type)
    {
        case WELFARE_NODE_TYPE_SIGN_IN_MONTH:
        {
            break;
        }
        case WELFARE_NODE_TYPE_NULL:
            break;
        default:
        {
            CHECK_ERR(0, -1, "type:{} error, id:{} nodeId:{}", pDesc->m_welfareId, pNodeDesc->m_nodeId);
        }
    }
    return 0;
}

int WelfareDescEx::CheckWelfareNodeAward(const WelfareNodeAward& stWelfareNodeAward)
{
    if (stWelfareNodeAward.m_aiParam.size() > 4)
    {
        const auto& iWelfareNodeAwardPrivilegeType = stWelfareNodeAward.m_aiParam[4];
        if (iWelfareNodeAwardPrivilegeType != 0)
        {
            if (iWelfareNodeAwardPrivilegeType <= proto_ff::WelfareNodeAwardPrivilegeType_MIN || iWelfareNodeAwardPrivilegeType >= proto_ff::WelfareNodeAwardPrivilegeType_MAX)
            {
                CHECK_ERR(0, -1, "invalid iWelfareNodeAwardPrivilegeType:{}", iWelfareNodeAwardPrivilegeType);
            }
        }
    }

    switch (stWelfareNodeAward.m_enWelfareNodeAwardType)
    {
        case WELFARE_NODE_AWARD_TYPE_WARE:
        {
            int iWareId = stWelfareNodeAward.m_aiParam[0];
            auto pDesc = ItemDesc::Instance()->GetDesc(iWareId);
            CHECK_NULL_WF(0, pDesc, "invalid iWareId:{}", iWareId);
            break;
        }
        case WELFARE_NODE_AWARD_TYPE_AWARD_ID:
        {
            int iRewardId = stWelfareNodeAward.m_aiParam[0];
            auto pDesc = RewardDesc::Instance()->GetDesc(iRewardId);
            CHECK_NULL_WF(0, pDesc, "invalid iRewardId:{}", iRewardId);
            break;
        }
        case WELFARE_LOOP_TYPE_NULL:
            break;
        default:
        {
            CHECK_ERR(0, -1, "m_enWelfareNodeAwardType:{} error", stWelfareNodeAward.m_enWelfareNodeAwardType);
            break;
        }
    }
    return 0;
}

int WelfareDescEx::CheckWelfareWorldID(const E_Welfare* pDesc)
{
    CHECK_NULL(0, pDesc);
    if (pDesc->m_astServerOpenUnixTimeRange.size() == 0)
    {
        return 0;
    }

    bool bExitEcept = false;
    std::set<int> setIncludeWorldID;
    std::set<int> setExceptWorldID;
    for (int i = 0; i < (int)pDesc->m_astServerOpenUnixTimeRange.size(); i++)
    {
        auto& stServerOpenUnixtimeRange = pDesc->m_astServerOpenUnixTimeRange[i];
        LOG_DEBUG(0, "welfareId:{} worldlist:{}", pDesc->m_welfareId, stServerOpenUnixtimeRange.m_szServerIDList.ToString());

        bool bContainAllOne = false; // 已保存所有服，所有服排斥其他配置
        bool bExitExceptOne = false; // 配置了，只能有一个排斥项
        std::set<int> setIncludeWorldIDOne; // 添加的服
        std::set<int> setExceptWorldIDOne; // 排除的服

        GetContainWorldOne(stServerOpenUnixtimeRange, setIncludeWorldIDOne, setExceptWorldIDOne, bContainAllOne, bExitExceptOne);
        if (bContainAllOne && pDesc->m_astServerOpenUnixTimeRange.size() != 1)
        {
            CHECK_ERR(0, -1, "contain all world must is only one {}", stServerOpenUnixtimeRange.m_szServerIDList.ToString());
        }

        if (bExitExceptOne)
        {
            if (bExitEcept)
            {
                CHECK_ERR(0, -1, "except type {}", stServerOpenUnixtimeRange.m_szServerIDList.ToString());
            }
            bExitEcept = true;
            int iRetCode = MergeWorldID(setExceptWorldID, setExceptWorldIDOne);
            CHECK_ERR(0, iRetCode, "duplicat except world ID");
        }
        else
        {
            int iRetCode = MergeWorldID(setIncludeWorldID, setIncludeWorldIDOne);
            CHECK_ERR(0, iRetCode, "duplicat include world ID");
        }
    }

    if (setIncludeWorldID.size() != setExceptWorldID.size())
    {
        CHECK_ERR(0, -1, "include world not equal except world");
    }

    for (auto id : setExceptWorldID)
    {
        auto iter = setIncludeWorldID.find(id);
        if (iter == setIncludeWorldID.end())
        {
            CHECK_ERR(0, -1, "except world not in include world, except:{}", id);
        }
    }
    return 0;
}

int WelfareDescEx::MergeWorldID(std::set<int>& setA, std::set<int>& setB)
{
    for (auto id : setB)
    {
        auto iter = setA.find(id);
        if (iter != setA.end())
        {
            CHECK_ERR(0, -1, "id:{} repeat in A and int B", id);
        }

        setA.insert(id);
    }
    return 0;
}

int WelfareDescEx::GetContainWorldOne(const ServerOpenUnixTimeRange& rstTimeRange, std::set<int>& setIncludeWorldID, std::set<int>& setExceptWorldID, bool& bContainAll, bool& bIsExcept)
{
    std::string sWorldID = rstTimeRange.m_szServerIDList.ToString();
    if (sWorldID.empty())
    {
        bContainAll = true;
        return 0;
    }

    if (sWorldID.size() < 2)
    {
        CHECK_ERR(0, -1, "invalid strIDRangeList:{}", sWorldID);
    }

    if (sWorldID[0] == '+')
    {
        return StrContainID(sWorldID, bContainAll, setIncludeWorldID);
    }
    else if (sWorldID[0] == '-')
    {
        bIsExcept = true;
        return StrContainID(sWorldID, bContainAll, setExceptWorldID);
    }
    else
    {
        CHECK_ERR(0, -1, "unknown type, strIDRangeList:{}", sWorldID);
    }
    return 0;
}

int WelfareDescEx::StrContainID(const std::string& strIDRangeList, bool& bIsAll, std::set<int>& setIDs)
{
    bIsAll = false;
    setIDs.clear();

    if (strIDRangeList.empty())
    {
        bIsAll = true;
        return 0;
    }

    std::vector<std::string> vecStrIDRange;
    NFStringUtility::SplitString(strIDRangeList, ",", vecStrIDRange);
    if (vecStrIDRange.empty())
    {
        CHECK_ERR(0, -1, "invalid strIDRangeList:{}", strIDRangeList);
    }

    for (const auto& strIDRange : vecStrIDRange)
    {
        std::vector<int> intArray;
        NFStringUtility::SplitStringToVector(strIDRange, "-", intArray);

        if (intArray.size() == 1)
        {
            setIDs.insert(intArray[0]);
        }
        else if (intArray.size() == 2)
        {
            for (int i = intArray[0]; i <= intArray[1]; i++)
            {
                setIDs.insert(i);
            }
        }
        else
        {
            CHECK_ERR(0, -1, "invalid strIDRange:%s", strIDRange.c_str());
        }
    }
    return 0;
}
